/**
 * 通知模型
 * @description 定义系统通知的数据结构和相关方法
 */

const mongoose = require('mongoose');

// 通知ID计数器模式
const NotificationIdCounterSchema = new mongoose.Schema({
    _id: { type: String, default: 'notificationId' },
    sequence_value: { type: Number, default: 0 }
});

const NotificationIdCounter = mongoose.model('NotificationIdCounter', NotificationIdCounterSchema);

// 通知模式
const NotificationSchema = new mongoose.Schema({
    notificationId: {
        type: Number,
        unique: true,
        required: true,
        description: '通知的唯一标识符，自动递增生成'
    },
    userId: {
        type: Number,
        required: true,
        index: true,
        description: '接收通知的用户ID，关联到用户信息表'
    },
    type: {
        type: String,
        enum: [
            'like',           // 点赞通知
            'comment',        // 评论通知
            'reply',          // 回复通知
            'follow',         // 关注通知
            'favorite',       // 收藏通知
            'message',        // 私信通知
            'system',         // 系统通知
            'video_upload',   // 视频上传通知
            'video_approved', // 视频审核通过
            'video_rejected', // 视频审核拒绝
            'mention'         // @提及通知
        ],
        required: true,
        index: true,
        description: '通知类型，包括点赞、评论、回复、关注、收藏、私信、系统通知等'
    },
    title: {
        type: String,
        required: true,
        maxlength: 100,
        description: '通知标题，最大长度100字符'
    },
    content: {
        type: String,
        required: true,
        maxlength: 500,
        description: '通知内容，最大长度500字符'
    },
    data: {
        type: mongoose.Schema.Types.Mixed,
        default: {},
        description: '通知相关的额外数据，存储为JSON格式'
    },
    fromUserId: {
        type: Number,
        default: null,
        index: true,
        description: '触发通知的用户ID，系统通知时为null'
    },
    targetType: {
        type: String,
        enum: ['video', 'comment', 'user', 'system'],
        default: null,
        description: '通知目标类型，可以是视频、评论、用户或系统'
    },
    targetId: {
        type: Number,
        default: null,
        description: '通知目标的ID，根据targetType确定具体含义'
    },
    isRead: {
        type: Boolean,
        default: false,
        index: true,
        description: '通知是否已读，true表示已读，false表示未读'
    },
    readAt: {
        type: Date,
        default: null,
        description: '通知阅读时间，记录用户阅读通知的时间'
    },
    isDeleted: {
        type: Boolean,
        default: false,
        index: true,
        description: '软删除标记，true表示已删除，false表示正常状态'
    },
    priority: {
        type: String,
        enum: ['low', 'normal', 'high', 'urgent'],
        default: 'normal',
        index: true,
        description: '通知优先级，分为低、普通、高、紧急四个级别'
    },
    expiresAt: {
        type: Date,
        default: null,
        description: '通知过期时间，过期后自动删除'
    },
    createAt: {
        type: Date,
        default: Date.now,
        index: true,
        description: '通知的创建时间'
    },
    updateAt: {
        type: Date,
        default: Date.now,
        description: '通知的最后更新时间'
    }
});

// 复合索引
NotificationSchema.index({ userId: 1, isRead: 1, createAt: -1 });
NotificationSchema.index({ userId: 1, type: 1, createAt: -1 });
NotificationSchema.index({ fromUserId: 1, createAt: -1 });
NotificationSchema.index({ expiresAt: 1 }, { expireAfterSeconds: 0 });

// 预保存钩子
NotificationSchema.pre('save', async function(next) {
    if (this.isNew) {
        try {
            const counter = await NotificationIdCounter.findByIdAndUpdate(
                'notificationId',
                { $inc: { sequence_value: 1 } },
                { new: true, upsert: true }
            );
            this.notificationId = counter.sequence_value;
        } catch (error) {
            return next(error);
        }
    }
    this.updateAt = new Date();
    next();
});

// 静态方法

/**
 * 创建通知
 * @param {Object} notificationData - 通知数据
 * @returns {Promise<Object>} 创建的通知
 */
NotificationSchema.statics.createNotification = async function(notificationData) {
    const {
        userId,
        type,
        title,
        content,
        data = {},
        fromUserId = null,
        targetType = null,
        targetId = null,
        priority = 'normal',
        expiresAt = null
    } = notificationData;
    
    const notification = new this({
        userId,
        type,
        title,
        content,
        data,
        fromUserId,
        targetType,
        targetId,
        priority,
        expiresAt
    });
    
    await notification.save();
    return notification.getSafeJSON();
};

/**
 * 批量创建通知
 * @param {Array} notificationsData - 通知数据数组
 * @returns {Promise<Array>} 创建的通知列表
 */
NotificationSchema.statics.createBatchNotifications = async function(notificationsData) {
    const notifications = [];
    
    for (const notificationData of notificationsData) {
        const notification = await this.createNotification(notificationData);
        notifications.push(notification);
    }
    
    return notifications;
};

/**
 * 获取用户通知列表
 * @param {Object} options - 查询选项
 * @returns {Promise<Object>} 通知列表和分页信息
 */
NotificationSchema.statics.getUserNotifications = async function(options) {
    const {
        userId,
        type = null,
        isRead = null,
        priority = null,
        page = 1,
        limit = 20
    } = options;
    
    const skip = (page - 1) * limit;
    
    const query = {
        userId,
        isDeleted: false
    };
    
    if (type) query.type = type;
    if (isRead !== null) query.isRead = isRead;
    if (priority) query.priority = priority;
    
    const notifications = await this.find(query)
        .sort({ createAt: -1 })
        .skip(skip)
        .limit(limit)
        .lean();
    
    const total = await this.countDocuments(query);
    
    return {
        notifications: notifications.map(notification => ({
            notificationId: notification.notificationId,
            type: notification.type,
            title: notification.title,
            content: notification.content,
            data: notification.data,
            fromUserId: notification.fromUserId,
            targetType: notification.targetType,
            targetId: notification.targetId,
            isRead: notification.isRead,
            readAt: notification.readAt,
            priority: notification.priority,
            createAt: notification.createAt
        })),
        pagination: {
            page,
            limit,
            total,
            pages: Math.ceil(total / limit)
        }
    };
};

/**
 * 标记通知为已读
 * @param {Object} options - 标记选项
 * @returns {Promise<Object>} 更新结果
 */
NotificationSchema.statics.markAsRead = async function(options) {
    const { userId, notificationIds = null, type = null } = options;
    
    let query = {
        userId,
        isRead: false,
        isDeleted: false
    };
    
    if (notificationIds && Array.isArray(notificationIds)) {
        query.notificationId = { $in: notificationIds };
    }
    
    if (type) {
        query.type = type;
    }
    
    const result = await this.updateMany(
        query,
        {
            $set: {
                isRead: true,
                readAt: new Date(),
                updateAt: new Date()
            }
        }
    );
    
    return {
        modifiedCount: result.modifiedCount,
        matchedCount: result.matchedCount
    };
};

/**
 * 删除通知
 * @param {Object} options - 删除选项
 * @returns {Promise<Object>} 删除结果
 */
NotificationSchema.statics.deleteNotifications = async function(options) {
    const { userId, notificationIds = null, type = null, olderThan = null } = options;
    
    let query = {
        userId,
        isDeleted: false
    };
    
    if (notificationIds && Array.isArray(notificationIds)) {
        query.notificationId = { $in: notificationIds };
    }
    
    if (type) {
        query.type = type;
    }
    
    if (olderThan) {
        query.createAt = { $lt: olderThan };
    }
    
    const result = await this.updateMany(
        query,
        {
            $set: {
                isDeleted: true,
                updateAt: new Date()
            }
        }
    );
    
    return {
        modifiedCount: result.modifiedCount,
        matchedCount: result.matchedCount
    };
};

/**
 * 获取未读通知数量
 * @param {number} userId - 用户ID
 * @param {string} [type] - 通知类型
 * @returns {Promise<number>} 未读通知数量
 */
NotificationSchema.statics.getUnreadCount = async function(userId, type = null) {
    const query = {
        userId,
        isRead: false,
        isDeleted: false
    };
    
    if (type) query.type = type;
    
    const count = await this.countDocuments(query);
    return count;
};

/**
 * 获取通知统计
 * @param {number} userId - 用户ID
 * @returns {Promise<Object>} 通知统计信息
 */
NotificationSchema.statics.getNotificationStats = async function(userId) {
    const [totalCount, unreadCount, typeStats] = await Promise.all([
        this.countDocuments({ userId, isDeleted: false }),
        this.countDocuments({ userId, isRead: false, isDeleted: false }),
        this.aggregate([
            {
                $match: { userId, isDeleted: false }
            },
            {
                $group: {
                    _id: '$type',
                    total: { $sum: 1 },
                    unread: {
                        $sum: {
                            $cond: [{ $eq: ['$isRead', false] }, 1, 0]
                        }
                    }
                }
            }
        ])
    ]);
    
    const typeStatsMap = {};
    typeStats.forEach(stat => {
        typeStatsMap[stat._id] = {
            total: stat.total,
            unread: stat.unread
        };
    });
    
    return {
        totalCount,
        unreadCount,
        typeStats: typeStatsMap
    };
};

/**
 * 清理过期通知
 * @returns {Promise<Object>} 清理结果
 */
NotificationSchema.statics.cleanupExpiredNotifications = async function() {
    const result = await this.deleteMany({
        expiresAt: { $lt: new Date() }
    });
    
    return {
        deletedCount: result.deletedCount
    };
};

/**
 * 获取系统通知
 * @param {Object} options - 查询选项
 * @returns {Promise<Object>} 系统通知列表
 */
NotificationSchema.statics.getSystemNotifications = async function(options) {
    const { page = 1, limit = 20, priority = null } = options;
    
    const skip = (page - 1) * limit;
    
    const query = {
        type: 'system',
        isDeleted: false
    };
    
    if (priority) query.priority = priority;
    
    const notifications = await this.find(query)
        .sort({ createAt: -1 })
        .skip(skip)
        .limit(limit)
        .lean();
    
    const total = await this.countDocuments(query);
    
    return {
        notifications: notifications.map(notification => ({
            notificationId: notification.notificationId,
            title: notification.title,
            content: notification.content,
            data: notification.data,
            priority: notification.priority,
            createAt: notification.createAt
        })),
        pagination: {
            page,
            limit,
            total,
            pages: Math.ceil(total / limit)
        }
    };
};

/**
 * 发送系统广播通知
 * @param {Object} notificationData - 通知数据
 * @param {Array} userIds - 用户ID数组
 * @returns {Promise<Array>} 创建的通知列表
 */
NotificationSchema.statics.broadcastSystemNotification = async function(notificationData, userIds) {
    const { title, content, data = {}, priority = 'normal', expiresAt = null } = notificationData;
    
    const notifications = userIds.map(userId => ({
        userId,
        type: 'system',
        title,
        content,
        data,
        priority,
        expiresAt
    }));
    
    return await this.createBatchNotifications(notifications);
};

// 实例方法

/**
 * 获取安全的JSON数据
 * @returns {Object} 安全的通知数据
 */
NotificationSchema.methods.getSafeJSON = function() {
    return {
        notificationId: this.notificationId,
        userId: this.userId,
        type: this.type,
        title: this.title,
        content: this.content,
        data: this.data,
        fromUserId: this.fromUserId,
        targetType: this.targetType,
        targetId: this.targetId,
        isRead: this.isRead,
        readAt: this.readAt,
        priority: this.priority,
        createAt: this.createAt,
        updateAt: this.updateAt
    };
};

/**
 * 标记为已读
 * @returns {Promise<Object>} 更新后的通知
 */
NotificationSchema.methods.markRead = async function() {
    this.isRead = true;
    this.readAt = new Date();
    this.updateAt = new Date();
    await this.save();
    return this.getSafeJSON();
};

/**
 * 检查是否过期
 * @returns {boolean} 是否过期
 */
NotificationSchema.methods.isExpired = function() {
    if (!this.expiresAt) return false;
    return new Date() > this.expiresAt;
};

/**
 * 检查是否可以删除
 * @param {number} userId - 用户ID
 * @returns {boolean} 是否可以删除
 */
NotificationSchema.methods.canDelete = function(userId) {
    return this.userId === userId;
};

const Notifications = mongoose.model('Notifications', NotificationSchema);

module.exports = Notifications;